﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;

namespace ArgusControls
{
	public class ParsingTextBox : FilterTextBox
	{
		private const string TryParseMethodName = "TryParse";
		private MethodInfo tryParseMethod;
		private Type type;
		private object value;

		public event RoutedEventHandler ValueChanged;

		public System.Globalization.NumberStyles NumbersStyle { get; protected set; }

		public object Value
		{
			get { return this.value; }
			set
			{
				if (value.GetType() != this.type)
					throw new Exception("wrong type.");
				this.value = value;
				this.Text = value.ToString();
				this.OnValueChanged();
			}
		}

		public Key AcceptKey { get; set; }

		protected ParsingTextBox(Type type)
			: base()
		{
			this.type = type;
			this.tryParseMethod = ParsingTextBox.GetTryParseMethod(this.type);
			this.NumbersStyle = System.Globalization.NumberStyles.Any;
			
			this.AcceptKey = Key.Enter;
			this.Value = Activator.CreateInstance(this.type);
		}

		private static MethodInfo GetTryParseMethod(Type type)
		{
			return type.GetMethod(
				"TryParse",
				BindingFlags.Public | BindingFlags.Static,
				null,
				new Type[] { typeof(string), typeof(System.Globalization.NumberStyles), typeof(IFormatProvider), type.MakeByRefType() },
				null);
		}

		public static ParsingTextBox CreateInstance(Type type)
		{
			if (ParsingTextBox.GetTryParseMethod(type) == null)
				return null;
			return new ParsingTextBox(type);
		}

		protected virtual void CheckText()
		{
			object[] para = new object[] { this.Text, this.NumbersStyle, null, Activator.CreateInstance(this.type) };
			if ((bool)this.tryParseMethod.Invoke(null, para) == true)
			{
				this.Value = para[3];
			}
			else
			{
				this.Text = this.Value.ToString();
			}
			this.SelectionStart = this.Text.Length;
		}

		protected override void OnLostFocus(RoutedEventArgs e)
		{
			this.CheckText();
			base.OnLostFocus(e);
		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			if (e.Key == this.AcceptKey)
				this.CheckText();
			base.OnKeyDown(e);
		}

		protected virtual void OnValueChanged()
		{
			if (this.ValueChanged != null)
				this.ValueChanged(this, new RoutedEventArgs());
		}
	}

	public abstract class ParsingTextBox<T> : ParsingTextBox
		where T : struct
	{
		public new T Value
		{
			get { return (T)base.Value; }
			set
			{
				base.Value = value;
			}
		}

		public new TextFilter Filter { get { return base.Filter; } set { } }

		public ParsingTextBox()
			: base(typeof(T))
		{
			base.Filter = this.GetFilter();
		}

		protected abstract TextFilter GetFilter();
	}
}
